package main

import (
	"fmt"
	"time"
)

/*
   在其他语言中，对于并发操作，通常是在一块共享内存中进行，即多个线程通过共享内存进行通信，会对共享内存中的一些变量进行并发操作，当然，这需要锁来保证并发安全性。
   在Go中则相反，其是通过通信来共享内存，这里就需要用到 TODO 通道channel 来通信 ,通过收发消息，能够以推送的方式协调并发事件，即事件发生时，把触发的消息推送给接收者

*/
func main() {
	//channelTest1()
	bufferChannel()
}

/*
   通道创建语法：使用make创建，通道类型为chan，string为该通道收发消息的类型，即这里只能接收和发送字符串类型的消息
*/
func channelCreate() {
	c := make(chan string)

	//通道接收一个消息
	c <- "消息1"
	//接收通道的消息并赋值给msg变量
	msg := <-c
	fmt.Println(msg)
}

/**
测试1：使用通道进行通信
*/
func channelTest1() {
	// 声明方式1
	//var ch1 chan  int
	//声明方式2
	channel := make(chan string)
	go sleep(channel)
	fmt.Println("我是主程序")
	//TODO 这里会阻塞等待goroutine执行完，接收通道信息后才会继续执行
	msg := <-channel
	//通道接收了多少个消息这里就可以接收到多少个消息，但是不能超过通过接收的消息总数
	msg2 := <-channel
	fmt.Println(msg)
	fmt.Println(msg2)
	fmt.Println("我是主程序最后的")
}

/**
TODO 缓冲通道：如果暂时没有接收者，可以先放到缓冲通道中，待有接收者了再进行消息消费，通过make(chan string,2)指定一个长度，即创建了一个固定长度为2的缓冲通道，这表示该通道只能接收两条消息
*/
func bufferChannel() {
	message := make(chan string, 2)
	message <- "消息1"
	message <- "消息2"
	//无法接收3条
	//message<-"消息3"
	// 关闭通道，关闭后该通道无法继续接收消息
	close(message)
	fmt.Println("接收消息完毕，休息2s")
	time.Sleep(time.Second * 2)
	receiver(message)
}

func receiver(channel chan string) {
	fmt.Println("开始接收消息...")
	for msg := range channel {
		fmt.Println(msg)
	}
}

func sleep(channel chan string) {
	time.Sleep(time.Second * 2)
	//sleep完后向通道发送消息
	channel <- "睡完了2s"
	channel <- "睡完了23s"
}
